package v1

import (
	"encoding/json"
	"errors"
	"io/ioutil"
	"net/http"
	"strconv"
	"web_framework/config"
	"web_framework/model"
	"web_framework/storage"

	"github.com/gin-gonic/gin"
	log "github.com/sirupsen/logrus"
)

type CommentAPI struct {
}

type CommentRequest struct {
	CommentID      *int   `json:"comment_id,omitempty"`
	MainCommentID  int    `json:"main_cmoment_id,omitempty"`
	ReplyCommentID int    `json:"reply_comment_id"`
	FromUID        *int   `json:"from_uid,omitempty"`
	ToUID          int    `json:"to_uid,omitempty"`
	ItemID         *int   `json:"itemid,omitempty"`
	ChannelID      *int   `json:"channel_id,omitempty"`
	Season         int    `json:"season,omitempty"`
	Episode        int    `json:"episode,omitempty"`
	Content        string `json:"content"`
	Good           int    `json:"good,omitempty"`
	Bad            int    `json:"bad,omitempty"`
	Vs             int    `json:"vs,omitempty"`
	Top            bool   `json:"top,omitempty"`
	Client         int    `json:"client,omitempty"`
	CreateIP       string `json:"create_ip"`
	Status         bool   `json:"status"`
}

type CommentResponse struct {
	Status   bool            `json:"status"`
	Error    string          `json:"error,omitempty"`
	Comments []model.Comment `json:"comments"`
}

func (a CommentAPI) Name() string {
	return "comment API"
}

func (a CommentAPI) Bind() {
	//if err := storage.ResetCommentTable(config.C.DB.DB); err != nil {
	//	log.WithError(err).Error("reset commment table")
	//} else {
	//	log.Info("reset comment table done")
	//}

	commentAPI := config.C.Router.Group("/comment")
	{
		commentAPI.POST("", createComment)
		commentAPI.DELETE("", softDeleteComment)
		commentAPI.PUT("", updateComment)
		commentAPI.GET("", getCommentsFromItemAndChannel)
	}
}

func createComment(c *gin.Context) {
	data, err := ioutil.ReadAll(c.Request.Body)
	if err != nil {
		handleError(c, err)
		return
	}

	var comment CommentRequest
	if err := json.Unmarshal(data, &comment); err != nil {
		handleError(c, err)
		return
	}

	if comment.FromUID == nil {
		handleError(c, errors.New("must specific the from_uid"))
		return
	}

	if comment.ItemID == nil {
		handleError(c, errors.New("must specific the item_id"))
		return
	}

	if comment.ChannelID == nil {
		handleError(c, errors.New("must specific the channel_id"))
		return
	}

	modelComment := requestToModel(&comment)
	modelComment.Status = true
	if err := storage.CreateComment(config.C.DB.DB, modelComment); err != nil {
		handleError(c, err)
	} else {
		c.JSON(http.StatusOK, gin.H{
			"status": 200,
			"resp": CommentResponse{
				Status: true,
			},
		})
	}
	return
}

func getCommentsFromItemAndChannel(c *gin.Context) {

	sItemID := c.Query("item_id")
	log.WithField("last page", sItemID).Info("get referer")
	sChannelID := c.Query("channel_id")

	if sItemID == "" || sChannelID == "" {
		handleError(c, errors.New("must specific the item_id and channel_id"))
		return
	}
	itemID, err := strconv.Atoi(sItemID)
	if err != nil {
		handleError(c, err)
	}
	channelID, err := strconv.Atoi(sChannelID)
	if err != nil {
		handleError(c, err)
	}

	if comments, err := storage.GetCommentsFromItemAndChannel(config.C.DB.DB, itemID, channelID); err != nil {
		handleError(c, err)
	} else {
		c.JSON(http.StatusOK, gin.H{
			"status": 200,
			"resp": CommentResponse{
				Status:   true,
				Comments: comments,
			},
		})
	}
	return

}

func softDeleteComment(c *gin.Context) {
	sCommentID := c.Query("comment_id")

	if sCommentID == "" {
		handleError(c, errors.New("must specific the comment_id"))
		return
	}

	commentID, err := strconv.Atoi(sCommentID)
	if err != nil {
		handleError(c, err)
	}

	if err := storage.DeleteCommentSoft(config.C.DB.DB, commentID); err != nil {
		handleError(c, err)
	} else {
		c.JSON(http.StatusOK, gin.H{
			"status": 200,
			"resp": CommentResponse{
				Status: true,
			},
		})
	}
	return
}

func updateComment(c *gin.Context) {
	data, err := ioutil.ReadAll(c.Request.Body)
	if err != nil {
		handleError(c, err)
		return
	}

	var comment CommentRequest
	if err := json.Unmarshal(data, &comment); err != nil {
		handleError(c, err)
		return
	}

	modelComment := requestToModel(&comment)
	if err := storage.UpdateComment(config.C.DB.DB, modelComment); err != nil {
		handleError(c, err)
	} else {
		c.JSON(http.StatusOK, gin.H{
			"status": 200,
			"resp": CommentResponse{
				Status: true,
			},
		})
	}
	return
}

func requestToModel(c *CommentRequest) *model.Comment {
	var itemID int
	var channelID int
	var fromUID int
	if c.ItemID == nil {
		itemID = 0
	} else {
		itemID = *c.ItemID
	}

	if c.ChannelID == nil {
		channelID = 0
	} else {
		channelID = *c.ChannelID
	}

	if c.FromUID == nil {
		fromUID = 0
	} else {
		fromUID = *c.FromUID
	}

	r := model.Comment{
		MainCommentID:  c.MainCommentID,
		ReplyCommentID: c.ReplyCommentID,
		FromUID:        fromUID,
		ToUID:          c.ToUID,
		ItemID:         itemID,
		ChannelID:      channelID,
		Season:         c.Season,
		Episode:        c.Episode,
		Content:        c.Content,
		Good:           c.Good,
		Bad:            c.Bad,
		Vs:             c.Vs,
		Top:            c.Top,
		Client:         c.Client,
		CreateIP:       c.CreateIP,
		Status:         c.Status,
	}

	if c.CommentID != nil {
		r.CommentID = *c.CommentID
	}

	return &r
}

func handleError(c *gin.Context, err error) {
	c.JSON(http.StatusOK, gin.H{
		"status": 200,
		"resp": CommentResponse{
			Status: false,
			Error:  err.Error(),
		},
	})
}
